package com.business.java2cache.channel;

import com.business.java2cache.core.CacheConstans;
import com.business.java2cache.core.CacheManager;
import com.business.java2cache.redis.RedisCache;
import com.business.java2cache.util.CacheException;
import com.business.java2cache.util.Command;
import com.business.java2cache.util.ProReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.util.SafeEncoder;

import java.util.List;

/**
 * 对外提供缓存操作方法，提供最全的方法,方便Cache实例类集成
 * Created by liuqinggang on 16/5/4.
 */
public class BaseCacheKit implements CacheKit {

    public final static byte LEVEL_1 = 1;
    public final static byte LEVEL_2 = 2;
    //读取配置文件
    public static ProReader java2CacheConfig = ProReader.getInstance(CacheConstans.CONFIG_FILE);


    String l2 = java2CacheConfig.getProperty("cache.L2.provider");
    private final static Logger log = LoggerFactory.getLogger(BaseCacheKit.class);


    //################ channel公共部分 开始  ###########################
    //###############################################################


    /**
     * 从缓存中取数据,先从1级取，再从2级取
     * region 为空,key的格式
     * ehcache:从默认的region中获取
     * memcache:namespace:key
     * redis:namespace:key
     *
     * @param key cache key
     * @return the cached object or null
     */
    public Object get(String key) {
        return get(null, key);
    }

    /**
     * 从缓存中取数据,先从1级取，再从2级取
     *
     * @param region cache region
     *               key格式：
     *               ehcache：用region,key
     *               memcache：namespace:region:key
     *               redis：使用hashs(region,key)
     * @param key    cache key
     * @return the
     * cached object or null
     */
    public Object get(String region, String key) {
        Object obj = null;
        if (key != null) {
            obj = CacheManager.get(LEVEL_1, region, key);
            if (obj == null) {
                obj = CacheManager.get(LEVEL_2, region, key);
                if (obj != null) {
                    CacheManager.set(LEVEL_1, region, key, obj, CacheConstans.defaultTime);
                }
            }
        }
        return obj;
    }


    /**
     * 获取数据,指定缓存的级别level
     *
     * @param level  cache level
     * @param region cache region
     * @param key    cache key
     * @return the cached object or null
     */
    public Object get(int level, String region, String key) {
        Object obj = null;
        if (key != null) {
            obj = CacheManager.get(level, region, key);
        }
        return obj;
    }

    /**
     * 获取取数据,指定缓存的级别level
     *
     * @param level cache level
     * @param key   cache key
     * @return the cached object or null
     */
    public Object get(int level, String key) {
        return get(level, CacheConstans.NUllRegion, key);
    }

    /**
     * Add an item to the cache
     *
     * @param region
     * @param key     cache key
     * @param value   cache value
     * @param seconds cache Expiration time
     */
    public void set(String region, String key, Object value, int seconds) {
        if (key != null) {
            if (value == null)
                remove(region, key);
            else {
                _sendEvictCmd(region, key);// 清除原有的一级缓存的内容
                CacheManager.set(LEVEL_1, region, key, value, seconds);
                CacheManager.set(LEVEL_2, region, key, value, seconds);
            }
        }
    }

    /**
     * 写入缓存
     *
     * @param region : Cache Region name
     * @param key    : Cache key
     * @param value  : Cache value
     */
    public void set(String region, String key, Object value) {
        set(region, key, value, CacheConstans.defaultTime);
    }

    /**
     * Add an item to the cache
     * region use default value
     *
     * @param key   cache key
     * @param value cache value
     *              seconds cache Expiration use default time
     */
    public void set(String key, Object value) {
        set(CacheConstans.NUllRegion, key, value, CacheConstans.defaultTime);
    }

    /**
     * Add an item to the cache
     * region use default value
     *
     * @param key   cache key
     * @param value cache value
     *              seconds cache Expiration use default time
     */
    public void set(String key, Object value, int seconds){
        set(CacheConstans.NUllRegion, key, value, seconds);
    }
    /**
     * Add an item to the cache
     *
     * @param level   cache level
     * @param region
     * @param key     cache key
     * @param value   cache value
     * @param seconds cache Expiration time
     */
    public void set(int level, String region, String key, Object value, int seconds) {
        if (key != null) {
            if (value == null)
                remove(region, key);
            else {
                _sendEvictCmd(region, key);// 清除原有的一级缓存的内容
                CacheManager.set(level, region, key, value, seconds);
            }
        }
    }

    /**
     * Add an item to the cache
     *
     * @param level  cache level
     * @param region
     * @param key    cache key
     * @param value  cache value
     *               seconds cache Expiration use default time
     */
    public void set(int level, String region, String key, Object value) {
        set(level, region, key, value, CacheConstans.defaultTime);
    }

    /**
     * Add an item to the cache
     *
     * @param level cache level
     * @param key   cache key
     * @param value cache value
     *              seconds cache Expiration use default time
     */
    public void set(int level, String key, Object value) {
        set(level, CacheConstans.NUllRegion, key, value, CacheConstans.defaultTime);
    }

    /**
     * @param key Cache key
     *            Remove an item from the cache
     */
    public void remove(String key) {
        _sendEvictCmd(CacheConstans.NUllRegion, key);
        CacheManager.remove(LEVEL_1, CacheConstans.NUllRegion, key);
        CacheManager.remove(LEVEL_2, CacheConstans.NUllRegion, key);
    }

    /**
     * 批量删除缓存
     *
     * @param region : Cache region name
     * @param keys   : Cache key
     */
    public void remove(String region, List keys) {
        remove(region, keys);
    }

    public void remove(List<String> keys) {
        for (String key : keys) {
            _sendEvictCmd(CacheConstans.NUllRegion, key);
        }
        CacheManager.batchRemove(LEVEL_1, CacheConstans.NUllRegion, keys);
        CacheManager.batchRemove(LEVEL_2, CacheConstans.NUllRegion, keys);
    }

    /**
     * 删除缓存
     *
     * @param region : Cache Region name
     * @param key    : Cache key
     */
    public void remove(String region, String key) {
        CacheManager.remove(LEVEL_1, region, key); // 删除一级缓存
        CacheManager.remove(LEVEL_2, region, key); // 删除二级缓存
        _sendEvictCmd(region, key); // 发送广播
    }


    /**
     * Clear the cache
     *
     * @param region : Cache region name
     */
    public void clear(String region) throws CacheException {
        CacheManager.clear(LEVEL_1, region);
        CacheManager.clear(LEVEL_2, region);
        _sendEvictCmd(region, null);
    }

    /**
     * 关闭到通道的连接
     */
    public void close() {
        CacheManager.shutdown(LEVEL_1);
        CacheManager.shutdown(LEVEL_2);
    }

    /**
     * update exprie time
     *
     * @param key
     * @param seconds
     */
    public Object exprie(String key, int seconds) {
        return exprie(CacheConstans.NUllRegion, key, seconds);
    }

    /**
     * update exprie time
     *
     * @param key
     * @param seconds
     */
    public Object exprie(String region, String key, int seconds) {
        CacheManager.exprie(LEVEL_1, region, key, seconds);
        CacheManager.exprie(LEVEL_2, region, key, seconds);
        return get(region, key);
    }

    /**
     * 发送清除缓存的广播命令，通知其他的1级缓存也删除
     *
     * @param region : Cache region name
     * @param key    : cache key
     */
    private void _sendEvictCmd(String region, String key) {
        //只有2级用redis时发送广播，其他接受到的会删除1级缓存，只有1级时此方法无效，不调用
        if (l2.equalsIgnoreCase(CacheConstans.redis)) {
            Command cmd = new Command(Command.OPT_DELETE_KEY, region, key);
            RedisCache redisCache = RedisCache.getInstance();
            Jedis jedis = redisCache._getJedis();
            try {
                jedis.publish(SafeEncoder.encode(CacheConstans.redischannel), cmd.toBuffers());
            } catch (Exception e) {
                log.error("Unable to delete cache,region=" + region + ",key=" + key, e);
            }
        }

    }

    //################ channel公共部分 结束  ###########################
    //################################################################


}
